package com.czk.netty.netty.groupchat.server;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

/**
 * 自己的处理器
 *
 * @Author:ChenZhangKun
 * @Date: 2021/1/18 20:25
 */
public class GroupChantServerHandler extends SimpleChannelInboundHandler<String> {
    /**
     * 定义channel组，管理所有的channel
     * GlobalEventExecutor.INSTANCE全局的事件执行器，是一个单例
     */
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    /**
     * 线程不安全，jdk1.8提供的时间api才是线程安全的
     */
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 表示连接建立，一旦连接建立就会触发此方法（第一个执行）
     * 将当前的channel加入到channelGroup中
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 拿到当前的channel
        Channel channel = ctx.channel();
        // 加入
        channelGroup.add(channel);
        // 将客户建立连接加入客户端的消息推送给其他在线的客户端
        // 该方法会遍历所有的channel完成推送
        channelGroup.writeAndFlush(simpleDateFormat.format(new Date())+" [客户端] " + channel.remoteAddress() + " 加入聊天\n");
    }

    /**
     * 表示channel处于一个活动的状态
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 服务器端提示
        System.out.println(simpleDateFormat.format(new Date())+" "+ctx.channel().remoteAddress() + "上线了");
    }

    /**
     * channel处于不活动状态时会提示
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(simpleDateFormat.format(new Date())+"  "+ctx.channel().remoteAddress() + "离线了");
    }

    /**
     * 表示断开连接了会触发
     * 触发此方法时，channelGroup会将其自动移除
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush(simpleDateFormat.format(new Date())+" [客户端] " + channel.remoteAddress() + " 离开了\n");
        System.out.println("channelGroup size" + channelGroup.size());
    }

    /**
     * 读取数据，将数据转发给在线的所有人
     *
     * @param channelHandlerContext
     * @param s
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
        // 获取当前channel
        Channel channel = channelHandlerContext.channel();
        // 遍历channelGroup，根据不同的情况处理消息
        channelGroup.forEach(x -> {
            // 排除自己
            if (!Objects.equals(x, channel)) {
                // 直接转发消息
                x.writeAndFlush(simpleDateFormat.format(new Date())+" [客户]" + channel.remoteAddress() + "发送了消息 " + s + "\n");
            } else {
                // 回显自己发送的消息给自己
                channel.writeAndFlush(simpleDateFormat.format(new Date())+" 自己发送了消息 " + s + "\n");
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 关闭通道
        ctx.close();
    }
}
